﻿using System.ComponentModel;
using Liphofra.Core;

namespace Liphofra.Mvvm.ViewModels
{
    /// <summary>
    /// A base class implementation for view model locators.
    /// </summary>
    /// <typeparam name="TViewModel">The type of the view model this instance can locate.</typeparam>
    /// <typeparam name="TDesignTimeViewModel">The type of the design time view model.</typeparam>
    public abstract class ViewModelLocatorBase<TViewModel, TDesignTimeViewModel>
        where TViewModel : class
        where TDesignTimeViewModel : class
    {
// ReSharper disable StaticFieldInGenericType
        private static bool? _isInDesignMode;
// ReSharper restore StaticFieldInGenericType
        private IServiceLocator _serviceLocator;
        private TViewModel _runtimeViewModel;
        private TDesignTimeViewModel _designTimeViewModel;

        /// <summary>
        /// Gets a value indicating whether the control is in design mode
        /// (running in Blend or Visual Studio).
        /// </summary>
        public bool IsInDesignMode
        {
            get
            {
                if (!_isInDesignMode.HasValue)
                {
                    _isInDesignMode = DesignerProperties.IsInDesignTool;
                }

                return _isInDesignMode.Value;
            }
        }

        /// <summary>
        /// Gets or sets the service locator.
        /// If no value is set by derived classes, the property is lazy-initialized to <see cref="Liphofra.Core.ServiceLocator.Instance"/>.
        /// </summary>
        /// <value>
        /// The service locator.
        /// </value>
        protected IServiceLocator ServiceLocator
        {
            get
            {
                if (_serviceLocator == null)
                {
                    _serviceLocator = Core.ServiceLocator.Instance;
                }

                return _serviceLocator;
            }

            set
            {
                _serviceLocator = value;
            }
        }

        /// <summary>
        /// Gets or sets the runtime view model.
        /// If no value is set by derived classes, this property is lazy-initialized when it's needed by using the view model factory.
        /// </summary>
        protected TViewModel RuntimeViewModel
        {
            get
            {
                if (_runtimeViewModel == null)
                {
                    var factory = ServiceLocator.Resolve<IViewModelFactory>();
                    RuntimeViewModel = factory.CreateViewModel<TViewModel>();
                }

                return _runtimeViewModel;
            }

            set
            {
                _runtimeViewModel = value;
            }
        }

        /// <summary>
        /// Gets or sets the design time view model.
        /// If no value is set by derived classes, this property is lazy-initialized when it's needed by using the view model factory.
        /// </summary>
        public TDesignTimeViewModel DesignTimeViewModel
        {
            get
            {
                if (_designTimeViewModel == null)
                {
                    var factory = ServiceLocator.Resolve<IViewModelFactory>();
                    _designTimeViewModel = factory.CreateViewModel<TDesignTimeViewModel>();
                }

                return _designTimeViewModel;
            }

            set
            {
                _designTimeViewModel = value;
            }
        }
    }
}